package com.robinmouren.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.robinmouren.constant.*;
import com.robinmouren.context.BaseContext;
import com.robinmouren.dto.QuotationPageDto;
import com.robinmouren.dto.UserLoginDto;
import com.robinmouren.entity.Enterprise;
import com.robinmouren.entity.OrderDetail;
import com.robinmouren.entity.OrderInfo;
import com.robinmouren.entity.User;
import com.robinmouren.exception.ErrorUserInfoException;
import com.robinmouren.exception.NullEnterpriseException;
import com.robinmouren.exception.NullOrderInfoException;
import com.robinmouren.exception.NullUserInfoException;
import com.robinmouren.mapper.UserMapper;
import com.robinmouren.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.robinmouren.utils.ListUtils;
import com.robinmouren.utils.StringUtils;
import com.robinmouren.vo.ClientInfoVo;
import com.robinmouren.vo.QuotationPageVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author Robinmouren
 * @since 2024-05-11
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {


    @Autowired
    private OrderServiceImpl orderService;
    @Autowired
    private OrderDetailServiceImpl orderDetailService;
    @Autowired
    private EnterpriseServiceImpl enterpriseService;

    /**
     * 用户登录校验
     *
     * @param loginDto
     * @return
     */
    @Override
    public User login(UserLoginDto loginDto) {
        // 获取账号密码
        String username = loginDto.getUsername();
        String password = loginDto.getPassword();

        // 获取用户信息
        User user = this.getOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username));

        // 非空判断
        if (user == null) {
            // 空指针异常抛出
            throw new NullUserInfoException(MessageConstant.USER_NOT_EXIST);
        }
        // 调用字符串工具对密码判断
        if (!StringUtils.md5(password).equals(user.getPassword())) {
            // 密码错误异常抛出
            throw new ErrorUserInfoException(MessageConstant.PASSWORD_ERROR);
        }
        // 判断用户状态是否禁用
        if (user.getStatus() == StatusConstant.DISABLE) {
            throw new ErrorUserInfoException(MessageConstant.USER_ACCOUNT_DISABLE);
        }
        // 判断用户是否已登录
        if (user.getIfLogin() == StatusConstant.IS_LOGIN) {
            throw new ErrorUserInfoException(MessageConstant.USER_IS_LOGIN);
        }


        /**
         * 每次登录时记录登陆时间
         * 创建函数当现在时间大于上次登陆时间时，将已登录改为未登录
         * 同时jwt也过期
         *
         * 函数
         * CREATE DEFINER=`root`@`localhost` PROCEDURE `Untitled`()
         * BEGIN
         * 	#Routine body goes here...
         * 	UPDATE `user` SET if_login = 0 where NOW() > DATE_ADD(login_time,INTERVAL 1 day);
         * END;
         *
         * 事件
         * CALL update_if_login_status()
         */

        // TODO 异步修改用户账号的状态
        this.update(user,
                new LambdaUpdateWrapper<User>()
                .set(User::getLoginTime, LocalDateTime.now())
                .set(User::getIfLogin, StatusConstant.IS_LOGIN)
                .eq(User::getId, user.getId())
        );

        return user;
    }

    /**
     * 用户注册
     * 只能注册客户端账号
     * 承运商账号由管理员提供
     * 司机账号可由承运商创建
     *
     * @param username
     * @param password
     */
    @Override
    public void register(String username, String password) {

        // 判断用户账号是否存在
        User one = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        if (one != null) {
            throw new ErrorUserInfoException(MessageConstant.USER_IS_EXIST);
        }

        // 将用户密码进行加密并添加用户
        // 设置状态值3：信息未补全
        User user = User.builder()
                .username(username)
                .password(StringUtils.md5(password))
                .identity(IdentityConstant.CLIENT)
                .status(StatusConstant.ENABLE)
                .ifLogin(StatusConstant.NOT_LOGIN)
                .infoStatus(StatusConstant.INFO_INCOMPLETE)
                .build();
        this.save(user);
    }


    /**
     * 用户退出登录
     * 退出登录时修改用户状态信息，1：已启用，2：已登录
     *
     * @param id
     */
    @Override
    public void quit(String id) {
        User user = this.getById(id);
        if(user == null){throw new NullUserInfoException(MessageConstant.USER_NOT_EXIST);}
        this.update(user,
                new LambdaUpdateWrapper<User>()
                        .set(User::getIfLogin, StatusConstant.NOT_LOGIN)
                        .eq(User::getId, id)
        );
        BaseContext.removeCurrentId();
    }


    /**
     * 询价单分页
     *
     * @param pageDto
     * @return
     */
    @Override
    public Page<QuotationPageVo> quotationPage(QuotationPageDto pageDto) {

        // 获取dto中的信息
        LocalDateTime startTime = pageDto.getStartTime();
        LocalDateTime endTime = pageDto.getEndTime();
        String input = pageDto.getInput();
        int status = pageDto.getStatus();
        String id = pageDto.getId();
        /**
         * 前端分别传来两个input选择器，创建选项对应的lambda表达式并存入map集合中
         * 获取对应的lambda表达式function
         */
        SFunction<OrderInfo, ?> function1 = OrderConstant.ORDER_INPUT_MAP.get(pageDto.getValue1());
        SFunction<OrderInfo, ?> function2 = OrderConstant.ORDER_INPUT_MAP.get(pageDto.getValue2());

        /**
         * 选择其中有些字段与其他并不属于同一个类，难以同时处理
         * 这里选择利用中间变量，判断是否选择了该选项，若没有则继续
         * 若选择了，则在最后获取到collect集合后进一步处理
         */
        String temporarilyInput = NumberConstant.NULL_STRING;
        // 获取第一个输入框的数据数据类型是否为空
        if (function1 == null) {
            // 若不在OrderInfo类中则下一步的分页操作不使用该字段，并将该字段暂时存储
            temporarilyInput = input;
            input = NumberConstant.NULL_STRING;
        }
        // 分页查询
        Page<OrderInfo> orderPage = new Page<>(pageDto.getPage(), pageDto.getPageSize());
        // 根据身份选择不同的方式
        if(pageDto.getIdentity().equals(IdentityConstant.CLIENT)){
            orderService.page(orderPage,
                    new LambdaQueryWrapper<OrderInfo>()
                            .like(!Objects.equals(input, NumberConstant.NULL_STRING), function1, input)
                            .gt(startTime != null, function2, startTime)
                            .lt(endTime != null, function2, endTime)
                            .eq(status != NumberConstant.ZERO, OrderInfo::getStatus, status)
                            .and(wrapper -> {
                                wrapper.eq(!Objects.equals(id, NumberConstant.NULL_STRING),OrderInfo::getUserId,id);
                            })
                            .orderByDesc(OrderInfo::getCreateTime)
            );
        }else{
            orderService.page(orderPage,
                    new LambdaQueryWrapper<OrderInfo>()
                            .like(!Objects.equals(input, NumberConstant.NULL_STRING), function1, input)
                            .gt(startTime != null, function2, startTime)
                            .lt(endTime != null, function2, endTime)
                            .eq(status != NumberConstant.ZERO, OrderInfo::getStatus, status)
                            .orderByDesc(OrderInfo::getCreateTime)
            );
        }
        // 获取返回类型的分页对象
        Page<QuotationPageVo> page = new Page<>();
        BeanUtils.copyProperties(orderPage, page, "records");

        // 对分页查询结果处理
        List<OrderInfo> records = orderPage.getRecords();
        List<QuotationPageVo> collect = records.stream().map(item -> {
            QuotationPageVo quotationPageVo = new QuotationPageVo();
            BeanUtils.copyProperties(item, quotationPageVo);
            // 获取货物细明的结果集合
            List<OrderDetail> list = orderDetailService
                    .list(new LambdaQueryWrapper<OrderDetail>()
                            .eq(OrderDetail::getOrderId, item.getId()));

            // 将货物细明中的货名提取出来
            List<String> goodsName = new ArrayList<>();
            for (OrderDetail orderDetail : list) {
                goodsName.add(orderDetail.getName());
            }
            // 去掉列表中的括号，空格暂不用去掉
            quotationPageVo.setGoodsName(ListUtils.removeStringListConclusion(goodsName));

            // 获取用户id，查询用户所在公司id
            Long userId = item.getUserId();
            User user = this.getOne(new LambdaQueryWrapper<User>().eq(User::getId, userId));
            if (user == null) {
                throw new NullUserInfoException(MessageConstant.USER_NOT_EXIST);
            }
            // 获取公司id
            Long companyId = user.getCompanyId();
            Enterprise enterprise = enterpriseService.getOne(new LambdaQueryWrapper<Enterprise>()
                    .eq(Enterprise::getId, companyId));
            if (enterprise == null) {
                throw new NullEnterpriseException(MessageConstant.ENTERPRISE_INFO_NULL);
            }
            quotationPageVo.setId(item.getId().toString());
            // 获取用户所在公司信息
            quotationPageVo.setUserId(user.getId().toString());
            quotationPageVo.setCompanyName(enterprise.getName());
            quotationPageVo.setContactName(user.getName());
            return quotationPageVo;
        }).collect(Collectors.toList());

        // 若第三方变量被使用，则对分页集合collect进一步处理
        if (!temporarilyInput.equals(NumberConstant.NULL_STRING)) {
            String finalTemporarilyInput = temporarilyInput;
            collect.forEach(item -> {
                if (item.getCompanyName().contains(finalTemporarilyInput)) {
                    collect.remove(item);
                }
            });
        }

        page.setRecords(collect);
        return page;
    }

    /**
     * 获取用户信息
     * @param id
     * @return
     */
    @Override
    public User userInfoGet(String id) {
        User user = this.getById(id);
        if(user == null){
            throw new NullUserInfoException(MessageConstant.USER_NOT_EXIST);
        }
        return user;
    }

    /**
     * 根据订单号获取客户信息
     * @return
     */
    @Override
    public ClientInfoVo clientGetByNumber(String orderNumber) {

        OrderInfo orderinfo = orderService.getOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderNumber, orderNumber));
        if(orderinfo == null){
            throw new NullOrderInfoException(MessageConstant.ORDER_IS_NULL);
        }
        Long userId = orderinfo.getUserId();
        User user = this.getById(userId);
        if(user == null){
            throw new NullUserInfoException(MessageConstant.USER_NOT_EXIST);
        }
        Long companyId = user.getCompanyId();
        Enterprise enterprise = enterpriseService.getById(companyId);
        if(enterprise == null){
            throw new NullEnterpriseException(MessageConstant.ENTERPRISE_INFO_NULL);
        }

        return ClientInfoVo.builder()
                .name(user.getName())
                .phone(user.getPhone())
                .username(user.getUsername())
                .companyName(enterprise.getName())
                .build();
    }
}
